/**
*@brief 实现wifi tcp客户端发送与接收
*相关资料：http://blog.csdn.net/roger_77/article/details/1453049

*构造函数CWiFi(string server_addr,const int port)
*server_addr为服务器的地址
*port为设置的端口号
*端口号设置只能为：1024～65535，一般较大为好

*start(),开启连接服务器线程

*sendData(char *send_data,int length):发送数据
*send_data为发送的数据，length为数据长度

*recvData(char *recv_data,int length)：接收数据（阻塞模式）
*recv_data为接收的数据，length为数据长度

*示例
*  CWiFi myWiFi("172.28.244.150",45455);//定义类
*  char data_[8] = {0};
*  int num = myWiFi.sendData(data_,8);//发送数据

* PS:Ubuntu使用时要关闭ufw防火墙！！
*/

#include "CWiFi.h"

CWiFi::CWiFi(string server_addr, const int port)
{
    this->isOpened = false;

    if ((this->sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
    {
        std::cout << "socket fail" << std::endl;
        return;
    }

    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(port);
    servaddr.sin_addr.s_addr = inet_addr(server_addr.c_str());

    this->keepAlive = 1; // 开启keepalive属性
    this->keepIdle = 3; // 如该连接在3秒内没有任何数据往来,则进行探测 
    this->keepInterval = 3; // 探测时发包的时间间隔为3 秒
    this->keepCount = 3; // 探测尝试的次数.如果第1次探测包就收到响应了,则后2次的不再发.

    setsockopt(this->sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&keepAlive, sizeof(keepAlive));
    setsockopt(this->sockfd, SOL_TCP, TCP_KEEPIDLE, (void*)&keepIdle, sizeof(keepIdle));
    setsockopt(this->sockfd, SOL_TCP, TCP_KEEPINTVL, (void *)&keepInterval, sizeof(keepInterval));
    setsockopt(this->sockfd, SOL_TCP, TCP_KEEPCNT, (void *)&keepCount, sizeof(keepCount));

};

CWiFi::~CWiFi()
{
    if (this->isOpened)
    {
        close(this->sockfd);
    }
};

bool CWiFi::is_opened()
{
    return this->isOpened;
};


int CWiFi::sendData(char *send_data, int length)
{
    if (this->isOpened)
    {
        int send_bytes = send(sockfd, send_data, length, MSG_NOSIGNAL);
        if(send_bytes <= 0)
        {    
            close(this->sockfd);       
            this->isOpened = false;
        }
        else
        {
            return send_bytes;
        }
    }
    else
    {
        return -1;
    }
};

int CWiFi::recvData(char *recv_data, int length)
{
    if(this->isOpened)
    {
        int recv_bytes = recv(sockfd, recv_data, length, MSG_NOSIGNAL);
        if(recv_bytes <= 0)
        {    
            close(this->sockfd);         
            this->isOpened = false;
            return -1;
        }
        else
        {
            return recv_bytes;
        }
    }
    else
    {
        usleep(500e3);
        return -1;
    }
    
};


void CWiFi::start()
{
    pthread_create(&connect_thread,NULL,connectServer,(void *)this);
}


void *CWiFi::connectServer(void *arg)
{
    CWiFi *this_ = (CWiFi *)arg;
    while (1)
    {
        if (connect(this_->sockfd, (struct sockaddr *)&this_->servaddr, sizeof(servaddr)) < 0)
        {
            perror("connect error...");
            this_->isOpened = false;
        }
        else
        {
            this_->isOpened = true;
            std::cout << "wifi init success!" << std::endl;
            pthread_create(&this_->detect_thread,NULL,detectState,(void *)this_);
            break;
        }
        sleep(1);
    }
}


void *CWiFi::detectState(void *arg)
{
    CWiFi *this_ = (CWiFi *)arg;
    while (1)
    {
        if(this_->isOpened)
        {
            sleep(1);
            continue;
        }
        else
        {
            if ((this_->sockfd = socket(AF_INET, SOCK_STREAM, 0)) == -1)
            {
                std::cout << "socket fail" << std::endl;
                continue;
            }
            setsockopt(this_->sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&this_->keepAlive, sizeof(this_->keepAlive));
            setsockopt(this_->sockfd, SOL_TCP, TCP_KEEPIDLE, (void*)&this_->keepIdle, sizeof(this_->keepIdle));
            setsockopt(this_->sockfd, SOL_TCP, TCP_KEEPINTVL, (void *)&this_->keepInterval, sizeof(this_->keepInterval));
            setsockopt(this_->sockfd, SOL_TCP, TCP_KEEPCNT, (void *)&this_->keepCount, sizeof(this_->keepCount));
            pthread_create(&this_->connect_thread,NULL,connectServer,(void *)this_);
            break;
        }
        sleep(1);
    }
}